using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization;
using libcharakter.Talente;
using libcharakter.ausrüstung;

namespace libcharakter
{
	public enum Geschlecht
	{
		W, // Weiblich
		M, // Mänlich
		IS // Intersexuell
	}
	public enum Stand
	{
		LD,	// ledig
		VH,	// verheiratet
		GT,	// getrennt lebend
		GS, // geschieden
		VW,	// verwitwet
		LP,	// verpartnert = Lebenspartnerschaft
		LA,	// entpartnert = Lebenspartnerschaft aufgehoben
		LV, // partnerhinterblieben = Lebenspartner verstorben
		FU  // Familienstand unbekannt
	}

	[Serializable]
    public class Charakter : Enemy
	{
        public static readonly int MAX_WUNDEN = 5;

		protected string m_name;
		protected Geschlecht m_geschlecht;
		protected int m_alter; // Berechnung durch kultur und rasse
		protected int m_grosse; // Berechnung durch kultur und rasse
		protected int m_gewicht; // Berechnung durch kultur und rasse
		protected string m_haarfarbe; // Berechnung durch kultur und rasse
		protected string m_augenfarbe; // Berechnung durch kultur und rasse
		protected string m_aussehen; // Berechnung durch kultur und rasse
		protected Stand m_stand;
		protected string m_title; // optimal
		protected int m_sozialstatus;
		protected string m_hintergrund; // optimal
        protected int m_Wunden; 

		protected Eigenschaften m_eigenschaften;
		protected BasisWerte m_basiswerte;

		protected SortedList<TalentType, List<abTalent>> m_talente;
        protected SortedList<AusruestungType, List<Ausruestung>> m_ausrustung;

		public string Name { get { return m_name; } }
		public Geschlecht Geschlecht { get { return m_geschlecht; } set { m_geschlecht = value; } }
		public int Alter { get { return m_alter; } }
		public int Größe { get { return m_grosse; } }
		public int Gewicht { get { return m_gewicht; } set { m_gewicht = value; } }
		public string Haarfarbe { get { return m_haarfarbe; } set { m_haarfarbe = value; } }
		public string Augenfarbe { get { return m_augenfarbe; } set { m_augenfarbe = value; } }
		public string Aussehen { get { return m_aussehen; } set { m_aussehen = value; } }
		public Stand Stand { get { return m_stand; } set { m_stand = value; } }
		public Eigenschaften Eigenschaften { get { return m_eigenschaften; }  }
		public BasisWerte BasisWerte { get { return m_basiswerte; } }

        public int Wunden
        {
            get { return m_Wunden; } 
        }
		public Charakter () : base(EnemySize.MittelGroß)
		{
		}

		public Charakter (string name, Geschlecht geschlecht,
		                  int sozialstatus, Stand stand,
		                  int mut, int kl, int ini, int ch, int ff, 
		                  int ge, int kon, int kk, int ges)
            : base(EnemySize.MittelGroß)
		{
			m_eigenschaften = new Eigenschaften (mut, kl, ini, ch, ff, ge, kon, kk, ges, this);
			m_basiswerte = new BasisWerte (this);
			m_name = name;
			m_geschlecht = geschlecht;
			m_sozialstatus = sozialstatus;
			m_stand = stand;

			m_talente = new SortedList<TalentType, List<abTalent>> ();
            m_ausrustung = new SortedList<AusruestungType, List<Ausruestung>>();

			for (TalentType i = 0; i < TalentType.MAX; i++) 
			{
				m_talente.Add(i, new List<abTalent>());
			}
            for (AusruestungType i = 0; i < AusruestungType.MAX; i++)
            {
                m_ausrustung.Add(i, new List<Ausruestung>());
            }

            m_Wunden = 0;
		}
	
		public bool Probe (string name, int v1, int v2, int v3, int erschwert, ref int rest)
		{
			abTalent talent = FindTalent(name);
			if(talent == null)
				return false;

			bool probe = talent.Probe(m_eigenschaften, v1,v2,v3, erschwert,ref rest);

			Console.WriteLine("[Probe] {0}: {1} ({4}) Ergbeniss: {2} Rest: {3} ({5}/{6}/{7})", name,
			                  (talent.Value <= 0) ? talent.Value : talent.Value - erschwert , probe, rest, talent.Value,
			                  v1, v2, v3);

			return probe;

		}
		public void AddTalent (abTalent talent)
		{
			for (TalentType i = 0; i < TalentType.MAX; i++)
			{
				for(int j = 0; j < m_talente[i].Count; j++)
				{
					if(m_talente[i][j].Name == talent.Name)
					{
						m_talente[i][j].BasicValue += talent.Value;
						return;
					}
				}
			}
			m_talente[talent.Type].Add(talent);
		}
        public bool AddAusruestung(Ausruestung item)
        {
            for (AusruestungType i = 0; i < AusruestungType.MAX; i++)
            {
                if (i == item.Type)
                {
                    if (item.Equip(this))
                    {
                        m_ausrustung [i].Add(item);
                        return true;
                    } else
                    {
                        Console.WriteLine("[Equip] Ausrüstung: {0} kann nicht angelegt werden", item.Name);
                    }
                }
            }
            return false;
        }
		public List<abTalent> GetTalente (TalentType type)
		{
			abTalent[] talente = new abTalent[m_talente[type].Count];

			m_talente[type].CopyTo(talente);

			return new List<abTalent>(talente);
		}
		protected void AddTalente (List<abTalent> talente)
		{
			foreach (var item in talente) 
			{
				AddTalent(item);
			}
		}
		public abTalent FindTalent (string name)
		{
			for (TalentType i = 0; i < TalentType.MAX; i++) 
			{
				for(int j = 0; j < m_talente[i].Count; j++)
				{
					if(m_talente[i][j].Name == name)
						return m_talente[i][j];
				}
			}
			return null;
		}
        public Ausruestung FindAusruestung(string name)
        {
            for (AusruestungType i = 0; i < AusruestungType.MAX; i++)
            {
                for (int j = 0; j < m_ausrustung[i].Count; j++)
                {
                    if (m_ausrustung [i] [j].Name == name)
                        return m_ausrustung [i] [j];
                }
            }
            return null;
        }
		public T FindTalent<T> (string name)
			where T : abTalent
		{
			return (T)FindTalent(name);
		}
        public Ausruestung FindAusruestung<T>(string name)
            where T : Ausruestung
        {
            return (T)FindAusruestung(name);
        }
		public void Save() 
		{
            Stream stream = null;
            try 
			{
                IFormatter formatter = new BinaryFormatter();
				if(!Directory.Exists("Helden"))
					Directory.CreateDirectory("Helden");

                stream = new FileStream("Helden/" + m_name + ".hld", FileMode.Create, FileAccess.Write, FileShare.None);
                formatter.Serialize(stream, this);
            } 
			catch (Exception e)
			{
				Console.WriteLine(e.Message);
            } 
			finally 
			{
                if (null != stream)
                    stream.Close();
            }
    	}
		public static Charakter Load(string name)
		{
	        Stream stream = null;
	        Charakter CHAR = null;
	        try 
			{
	            IFormatter formatter = new BinaryFormatter();
	            stream = new FileStream("Helden/" + name + ".hld", FileMode.Open, FileAccess.Read, FileShare.None);
	            CHAR = (Charakter)formatter.Deserialize(stream);
	        } 
			catch 
			{

	        } 
			finally
			{
	            if (null != stream)
	                stream.Close();
	        }
	        return CHAR;
    	}
		public void Update ()
		{
			m_eigenschaften.Update(this);
			m_basiswerte.Update(this);

		}
        public void AddWunde()
        {
            if (m_Wunden >= MAX_WUNDEN)
                throw new OdtkExitus(this);
            else
            {
                m_Wunden += 1;
                Eigenschaften.AddWunde();
            }
        }
        public void RemWunde()
        {
            if (m_Wunden == 0)
                return;
            m_Wunden -= 1;
            Eigenschaften.RemWunde();
        }
		public override string ToString ()
		{
			string ret = string.Format("{0}:\nRasse: {1}\nKultur: {2}\nGeschlecht: {3}\nAlter:{4}\n", Name, "", "", Geschlecht, Alter);
			ret += string.Format("Schritt: {0}\nStein: {1}\nHaarfarbe: {2}\nAugenfarbe: {3}\n", Größe, Gewicht, Haarfarbe, Augenfarbe);
			ret += string.Format("{0}\n",Aussehen);
			ret += "===========================================\n";
			ret += Eigenschaften.ToString() + "\n";
			ret += BasisWerte.ToString() + "\n";
			ret += "===========================================\n";

			for (TalentType i = 0; i < TalentType.MAX; i++) 
			{
				ret += string.Format("{0}\n", ((TalentType)i));

				foreach (var item in m_talente[(TalentType)i]) 
				{
					ret += item.ToString() + "\n";
				}
				ret += "===========================================\n";
			}

			return ret;
		}
	}
}

